use std::rc::Rc;

use super::{expr::SyntaxExpression, syntaxResult::SyntaxResult, token::SyntaxToken};
pub enum Stmt {
    Expression(ExpressionStmt),
    Block(BlockStmt),
    While(WhileStmts),
    If(IfStmts),
    Break(BreakStmt),
    Return(ReturnStmt),
    Printer(PrinterStmt),
    Function(FunctionStmts),
    VariableDeclaration(VariableDeclarationStmt),
}
impl Stmt {
    pub fn accept<T>(&self, visitor: &dyn StmtVisit<T>) -> Result<T, SyntaxResult> {
        match self {
            Self::Expression(v) => v.accept(visitor),
            Self::If(v) => v.accept(visitor),
            Self::Block(v) => v.accept(visitor),
            Self::While(v) => v.accept(visitor),
            Self::Break(v) => v.accept(visitor),
            Self::Return(v) => v.accept(visitor),
            Self::Printer(v) => v.accept(visitor),
            Self::Function(v) => v.accept(visitor),
            Self::VariableDeclaration(v) => v.accept(visitor),
        }
    }
}

pub struct ExpressionStmt {
    pub expression: SyntaxExpression,
}

// 块语句;
pub struct BlockStmt {
    pub statements: Vec<Stmt>,
}
pub struct PrinterStmt {
    pub expression: SyntaxExpression,
}
pub struct VariableDeclarationStmt {
    pub name: SyntaxToken,
    pub initializer: Option<SyntaxExpression>,
}
// IF 语句;
pub struct IfStmts {
    pub condition: SyntaxExpression,
    pub thenBranch: Box<Stmt>,
    pub elseBranch: Option<Box<Stmt>>,
}
pub struct WhileStmts {
    pub condition: SyntaxExpression,
    pub body: Box<Stmt>,
}
pub struct FunctionStmts {
    pub name: SyntaxToken,
    pub params: Rc<Vec<SyntaxToken>>,
    pub body: Rc<Vec<Stmt>>,
}
pub struct BreakStmt{
    pub token:SyntaxToken,
}
pub struct ReturnStmt {
    pub keyword: SyntaxToken,
    pub value: Option<SyntaxExpression>,
}
pub trait StmtVisit<T> {
    fn visitExpressionStmt(&self, expr: &ExpressionStmt) -> Result<T, SyntaxResult>;
    fn visitBlockStmt(&self, expr: &BlockStmt) -> Result<T, SyntaxResult>;
    fn visitPrinterStmt(&self, expr: &PrinterStmt) -> Result<T, SyntaxResult>;
    fn visitVariableStmt(&self, expr: &VariableDeclarationStmt) -> Result<T, SyntaxResult>;
    fn visitFunctionStmt(&self, expr: &FunctionStmts) -> Result<T, SyntaxResult>;
    fn visitIfStmt(&self, expr: &IfStmts) -> Result<T, SyntaxResult>;
    fn visitWhileStmt(&self, expr: &WhileStmts) -> Result<T, SyntaxResult>;
    fn visitBreakStmt(&self, expr: &BreakStmt) -> Result<T, SyntaxResult>;
    fn visitReturnStmt(&self, expr: &ReturnStmt) -> Result<T, SyntaxResult>;
}

impl ExpressionStmt {
    pub fn accept<T>(&self, visitor: &dyn StmtVisit<T>) -> Result<T, SyntaxResult> {
        visitor.visitExpressionStmt(self)
    }
}
impl BlockStmt {
    pub fn accept<T>(&self, visitor: &dyn StmtVisit<T>) -> Result<T, SyntaxResult> {
        visitor.visitBlockStmt(self)
    }
}

impl PrinterStmt {
    pub fn accept<T>(&self, visitor: &dyn StmtVisit<T>) -> Result<T, SyntaxResult> {
        visitor.visitPrinterStmt(self)
    }
}
impl VariableDeclarationStmt {
    fn accept<T>(&self, visitor: &dyn StmtVisit<T>) -> Result<T, SyntaxResult> {
        visitor.visitVariableStmt(self)
    }
}

impl IfStmts {
    fn accept<T>(&self, visitor: &dyn StmtVisit<T>) -> Result<T, SyntaxResult> {
        visitor.visitIfStmt(self)
    }
}
impl WhileStmts {
    fn accept<T>(&self, visitor: &dyn StmtVisit<T>) -> Result<T, SyntaxResult> {
        visitor.visitWhileStmt(self)
    }
}
impl FunctionStmts {
    fn accept<T>(&self, visitor: &dyn StmtVisit<T>) -> Result<T, SyntaxResult> {
        visitor.visitFunctionStmt(self)
    }
}
impl BreakStmt {
    fn accept<T>(&self, visitor: &dyn StmtVisit<T>) -> Result<T, SyntaxResult> {
        visitor.visitBreakStmt(self)
    } 
}
impl ReturnStmt {
    fn accept<T>(&self, visitor: &dyn StmtVisit<T>) -> Result<T, SyntaxResult> {
        visitor.visitReturnStmt(self)
    }
}
